/*###################################################################
  > File Name: storage/task/utils.c
  > Author: Vurtune
  > Mail: vurtune@foxmail.com
  > Created Time: Tue 28 Mar 2017 11:48:16 AM CST
###################################################################*/
#include "config.h"

#define DBG_SUBSYS S_LIBTASK

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "adt.h"
#include "sysy_lib.h"
#include "lich_md.h"
#include "md_map.h"
#include "lichstor.h"
#include "yid.h"
#include "balance.h"
#include "dbg.h"
#include "stor_ctl.h"
#include "system.h"

/**
 * @todo check fileinfo.attr
 *
 * @param pool
 * @param fileid
 * @return
 */
int vol_is_deleting(const fileid_t *fileid, int *result)
{
        int ret;
        fileinfo_t fileinfo;

        *result = 0;

        DBUG("chunk %s %p\n", id2str(fileid), fileid);
        ret = stor_ctl_getattr(fileid, &fileinfo);
        if (unlikely(ret)) {
                if (ENOENT == ret) {
                        *result = TRUE;
                } else {
                        GOTO(err_ret, ret);
                }
        } else {
                *result = (fileinfo.attr & __FILE_ATTR_DELETE__) == 0 ? 0 : 1;
        }

        return 0;
err_ret:
        return ret;
}

static int utils_iterator(const char *pool, const char *dir, func_int3_t func, void *arg)
{
        int ret, done = 0;
        uint64_t offset = 0, offset2 = 0;
        fileid_t fid;
        int delen;
        struct dirent *de0, *de;
        char uuid[MAX_NAME_LEN] = {};

        ret = stor_lookup1(pool, dir, &fid);
        if (unlikely(ret)) {
                GOTO(err_ret, ret);
        }

        get_uuid(uuid);
        ret = stor_listpool_open(&fid, uuid);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        de0 = NULL;
        while (done == 0) {
                ret = stor_listpool(&fid, uuid, offset, (void **)&de0, &delen);
                if (unlikely(ret)) {
                        GOTO(err_close, ret);
                }

                if (delen == 0) {
                        break;
                }

                offset2 = 0;
                dir_for_each(de0, delen, de, offset2) {
                        if (strlen(de->d_name) == 0) {
                                done = 1;
                                break;
                        } else if (delen - (int)offset2 < (int)(sizeof(*de) + MAX_NAME_LEN)) {
                                break;
                        }

                        offset += de->d_reclen;

                        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
                                continue;
                        }

                        ret = func((void *)pool, &fid, de->d_name, arg);
                        if (unlikely(ret))
                                GOTO(err_close, ret);

                }

                yfree((void **)&de0);
        }

        if (de0)
                yfree((void **)&de0);

        stor_listpool_close(&fid, uuid);

        return 0;
err_close:
        stor_listpool_close(&fid, uuid);
err_ret:
        return ret;
}

static int __utils_pool_remove_isempty__(void *pool, void *_fid, void *_name, void *_empty)
{
        (void) pool;
        (void) _fid;
        (void) _name;

        *(int *)_empty = 0;

        return 0;
}

static int __utils_pool_remove_isempty(void *pool, void *_fid, void *_name, void *_empty)
{
        int ret;
        char name[MAX_NAME_LEN];

        (void) pool;
        (void) _fid;

        sprintf(name, "/%s", (char *)_name);
        if (strcmp((char *)_name, "system")) {
                ret = utils_iterator(pool, name, __utils_pool_remove_isempty__, _empty);
                if (unlikely(ret)) {
                        if (ret != ENOSPC)
                                GOTO(err_ret, ret);
                }
        }

        return 0;
err_ret:
        return ret;
}

static int __utils_pool_drop(void *node, void *pool)
{
        int ret;

        ret = node_pooldrop(node, pool);
        if (unlikely(ret)) {
                /* nothing todo */
        }

        return 0;
}

int task_pool_remove(const char *pool)
{
        int ret;
        int empty = 1;

        ret = utils_iterator(pool, "/", __utils_pool_remove_isempty, &empty);
        if (unlikely(ret)) {
                if (ret == ENOKEY || ret == ENOSPC) {

                } else {
                        GOTO(err_ret, ret);
                }
        }

        if (!empty) {
                ret = ENOTEMPTY;
                GOTO(err_ret, ret);
        }

        // 清除etcd记录
        ret = system_pool_del(pool);
        if (unlikely(ret)) {
                if (ret == ENOENT) {

                } else {
                        if (ret == EPERM)
                                ret = EAGAIN;
                        GOTO(err_ret, ret);
                }
        }

        // 清除各个节点上的相关信息
        ret = cluster_listnode_iterator(__utils_pool_drop, (void *)pool);
        if (unlikely(ret)) {
                GOTO(err_ret, ret);
        }

        DINFO("pool %s removed\n", pool);
        return 0;
err_ret:
        return ret;
}
